﻿using DGZImp.Core.Exceptions;
using DGZImp.Core.Extensions;
using DGZImp.Core.Services;
using DGZImp.Core.Utilities;
using DGZImp.MdsProject.Base;
using DGZImp.MdsProject.Devices.Base;
using DGZImp.MdsProject.Devices.Helper;
using DGZImp.MdsProject.Devices.Models;
using DGZImp.MdsProject.DomainModels;
using DGZImp.MdsProject.Helper;
using DGZImp.MdsProject.Services;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Nomad.Iot;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DGZImp.MdsProject.Devices
{
    /// <summary>
    /// 生产设备
    /// </summary>
    public class Productor : BaseDevice
    {
        public ProductorData Data { get; set; }

        public RealDeviceTypeEmun Type { get; set; }

        public string Code { get; set; }

        public Productor(string id, string name, IIotServe serve, RealDeviceTypeEmun type, string code) : base(id, name, serve)
        {
            Type = type;
            Data = new ProductorData();
            Code = code ?? name;
            serve.OnWebSocketDataReceive += DataReceiveHandler;
        }

        public void DataReceiveHandler(object sender, string data)
        {
            var tmp = new ProductorData();
            if (data.IsNullOrEmpty())
            {
                Data = tmp;
                return;
            }
            try
            {
                var obj = JObject.Parse(data);
                if (obj["Value"] != null && obj["Value"]["Result"] != null)
                {
                    var lst = (JArray)obj["Value"]["Result"];
                    var current = lst.Where(x => x["DeviceCode"].ToString() == Code).FirstOrDefault();
                    try
                    {
                        if (current != null)
                        {
                            tmp.Code = current["DeviceCode"].ToString();
                            tmp.Name = current["DeviceName"].ToString();
                            tmp.AddrDeviceCode = current["TaskID"].ToString();
                            tmp.AddrOpenDoor = current["OpenDoor"].ToString();
                            tmp.AddrButtingUp = current["ButtingUp"].ToString();
                            tmp.RefreshTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
                            tmp.TaskId = current["TaskCode"].ToString();
                            tmp.Detected = current["Detected"].ToString();
                            tmp.RequestDevice = current["RequestDevice"].ToString();
                            tmp.AddrReturnToPosition = current["ReturnToPosition"].ToString();
                            var status = current["Status"].ToString();
                            tmp.Status = (ProductorStatusEmun)Convert.ToInt32(string.IsNullOrEmpty(status) || status.ToUpper().Equal("NULL") ? "0" : status);
                            var remoteV = current["RemoteV"].ToString();
                            tmp.Remote = (ProductorRemoteEnum)Convert.ToInt32(string.IsNullOrEmpty(remoteV) || remoteV.ToUpper().Equal("NULL") ? "0" : remoteV);
                            var finishedQuantity = current["FinishQuantity"].ToString();
                            tmp.FinishedQuantity = Convert.ToDecimal(string.IsNullOrEmpty(finishedQuantity) ? "0" : finishedQuantity);
                        }
                    }
                    catch (Exception ex)
                    {

                        SysLogger.LogError($"SCADA数据响应失败：{current}");
                        throw ex;
                    }

                    //判断当前设备状态 是否生产完成，若完成，则依据任务号更新任务状态
                    this.DataChangeHandler();
                }
                else
                {
                    SysLogger.LogError($"SCADA数据响应失败：{data}");
                }
            }
            catch (Exception e)
            {
                SysLogger.LogError(e, $"SCADA数据解析失败");
            }
            Data = tmp;
        }

        private async void DataChangeHandler()
        {
            if (Data == null) return;
            if (Data.Status != ProductorStatusEmun.生产结束) return;


            if (string.IsNullOrEmpty(Data.TaskId))
            {
                SysLogger.LogError($"当前设备 {Code}/{Name} 上报生产完成，但无 生产任务ID信息");
                return;
            }
            try
            {
                SysLogger.LogInformation($"开始处理生产设备 生产完成信号，任务ID：{Data.TaskId}");
                var prdTaskService = ServiceProviderAccessor.ServiceProvider.GetService<Mds_ProductionTaskService>();
                await prdTaskService.FinishProductionTask(Convert.ToInt64(Data.TaskId), Data);
            }
            catch (Exception ex)
            {
                SysLogger.LogError(ex, "处理生产完成信号异常");
            }

        }

        [MdsAction("发送指令", "发送一个交互指令给设备")]
        public async Task<OperateResult> SendCommandAsync([MdsParameter("指令类型")] ProductorCommandEmun command,
            [MdsParameter("AGV车设备号")] string requestDevice = null, [MdsParameter("当前生产任务号:")] string taskCode = null)
        {
            var res = new OperateResult("");
            var data = new SendData();
            var tmpTask = string.IsNullOrEmpty(taskCode) ? Data.TaskId : taskCode;
            data.VariableCodes = new List<string>() { Data.AddrDeviceCode };
            data.VariableValues = new List<object>() { taskCode };
            switch (command)
            {
                case ProductorCommandEmun.无指令:
                    throw new AppException("没有指定需要下发的指令");
                case ProductorCommandEmun.取货到位:
                    if (Type != RealDeviceTypeEmun.PRD_YX)
                        throw new AppException("此指令仅可下发到压机设备");
                    data.VariableCodes.Add(Data.AddrButtingUp);
                    data.VariableValues.Add("1");
                    break;
                case ProductorCommandEmun.取货完成:
                    if (Type != RealDeviceTypeEmun.PRD_HF && Type != RealDeviceTypeEmun.PRD_SJ)
                        throw new AppException("此指令仅可下发到混粉机或烧结炉设备");
                    data.VariableCodes.Add(Data.AddrReturnToPosition);
                    data.VariableValues.Add("1");
                    break;
                case ProductorCommandEmun.放货到位:
                    if (Type != RealDeviceTypeEmun.PRD_SJ)
                        throw new AppException("此指令仅可下发到烧结炉设备");
                    data.VariableCodes.Add(Data.AddrButtingUp);
                    data.VariableValues.Add("1");
                    break;
                case ProductorCommandEmun.放货完成:
                    if (Type != RealDeviceTypeEmun.PRD_HF)
                        throw new AppException("此指令仅可下发到混粉设备");
                    //放货完成时，同步写入当前生产的任务信息
                    data.VariableCodes.Add(Data.AddrReturnToPosition);
                    data.VariableValues.Add("1");
                    break;
                default:
                    break;
            }
            //加入AGV设备号 20241125
            if (!string.IsNullOrEmpty(requestDevice))
            {
                data.VariableCodes.Add(Data.RequestDevice);
                data.VariableValues.Add(requestDevice);
            }
            if (data.VariableCodes.Any(x => x.IsNullOrEmpty()))
            {
                throw new AppException($"下发设备对接指令时未获取到SCADA的控制点位：设备[{Code}]，指令[{command.ToString()}]");
            }
            var sendData = new
            {
                Name = "BATCHWRITE",
                MessageGuid = "*Guid*",
                SessionID = "*SessionId*",
                PK_UPPER_ENTITY = "411b6608-9fc4-4d2b-945e-d38f351f000c",
                Arguments = new object[]{
                    new {
                        VariableCodes = data.VariableCodes,
                        VariableValues = data.VariableValues,
                        MessageGuid = "*Guid*",
                        SessionID = "*SessionId*",
                        PK_UPPER_ENTITY = "411b6608-9fc4-4d2b-945e-d38f351f000c",
                    }
                }
            };
            SysLogger.LogInformation($"下发设备对接指令：设备[{Code}]，指令[{command.ToString()}],指令:" + JsonConvert.SerializeObject(sendData));
            var sendRes = await ((WebSocketServe)Serve).SendRequestAsync(JsonConvert.SerializeObject(sendData));
            if (!sendRes.IsSuccess)
                throw new AppException(sendRes.Message);
            SysLogger.LogInformation($"下发指令结果：{sendRes.Content}");
            var resObj = JObject.Parse(sendRes.Content);
            if (resObj["Value"]?["Quality"].ToString() == "GOOD")
            {
                res.IsSuccess = true;
            }
            else
            {
                throw new AppException("设备指令下发成功，但SCADA响应失败");
            }
            return res;
        }

    }

    public class SendData
    {
        public List<string> VariableCodes { get; set; }
        public List<object> VariableValues { get; set; }
    }

    public class ProductorData
    {
        [Description("01.设备编码")]
        public string Code { get; set; }

        [Description("02.设备名称")]
        public string Name { get; set; }

        [Description("03.设备状态")]
        public ProductorStatusEmun Status { get; set; }

        [Description("04.控制状态")]
        public ProductorRemoteEnum Remote { get; set; }

        [Description("05.货物状态")]
        public string Detected { get; set; }

        [Description("06.当前任务号:")]
        public string TaskId { get; set; }

        /// <summary>
        /// 下发指令到的设备号
        /// </summary>
        [Description("07.SCADA指令设备编号：")]
        public string AddrDeviceCode { get; set; }
        /// <summary>
        /// 请求开门信号地址
        /// </summary>
        public string AddrOpenDoor { get; set; }
        /// <summary>
        /// 对接到位
        /// </summary>
        public string AddrButtingUp { get; set; }
        /// <summary>
        /// 退出到位
        /// </summary>
        public string AddrReturnToPosition { get; set; }

        /// <summary>
        /// 当前完工数量
        /// </summary>
        [Description("08.当前完工数量：")]
        public decimal FinishedQuantity { get; set; }

        /// <summary>
        /// 请求设备
        /// </summary>
        [Description("06.对接请求设备")]
        public string RequestDevice { get; set; }

        [Description("99.刷新时间")]
        public string RefreshTime { get; set; }
    }
}
